package chainmaker

import (
	"errors"

	"github.com/coreos/go-oidc/v3/oidc"
	"golang.org/x/net/context"
	"golang.org/x/oauth2"

	"chainmaker.org/chainmaker/smarteditor/conf"
)

var (
	normalErr = errors.New("error")
)

// Oidc open id connection
// parse openid token
// fyi https://github.com/coreos/go-oidc/blob/v3/example/idtoken/app.go
func Oidc(code, redirectURL string) (*OpenIdInfo, error) {
	ctx := context.Background()

	issuer := conf.Wide.ChainMakerOAuthServer + conf.Wide.ChainMakerBaseUrl
	provider, err := oidc.NewProvider(ctx, issuer)
	if err != nil {
		log.Debugf("[Oidc] connect oauth server failed. err:%v", err)
		return nil, errors.New("connect oauth server failed.  " + err.Error())
	}

	oidcConfig := &oidc.Config{
		ClientID: conf.Wide.ChainMakerClientId,
	}
	verifier := provider.Verifier(oidcConfig)

	config := oauth2.Config{
		ClientID:     conf.Wide.ChainMakerClientId,
		ClientSecret: conf.Wide.ChainMakerClientSecret,
		Endpoint:     provider.Endpoint(),
		RedirectURL:  redirectURL,
		Scopes:       []string{oidc.ScopeOpenID},
	}
	oauth2Token, err := config.Exchange(ctx, code)
	if err != nil {
		log.Debugf("[Oidc] failed to exchange token. err:%v", err)
		return nil, err
	}

	log.Debugf("[Oidc] parse token success. refresh token:%v, access token:%v", oauth2Token.RefreshToken, oauth2Token.AccessToken)

	rawIDToken, ok := oauth2Token.Extra("access_token").(string)
	if !ok {
		log.Debugf("[Oidc] no access token field in oauth2 toke")
		return nil, normalErr
	}

	idToken, err := verifier.Verify(ctx, rawIDToken)
	if err != nil {
		log.Debugf("[Oidc] failed to verify id Token, err:%v", err)
		return nil, err
	}

	openIdInfo := &OpenIdInfo{}
	err = idToken.Claims(openIdInfo)
	if err != nil {
		log.Debugf("[Oidc] unmarshal token info failed, err:%v", err)
		return nil, err
	}
	openIdInfo.AccessToken = rawIDToken
	openIdInfo.RefreshToken = oauth2Token.RefreshToken

	return openIdInfo, nil
}
